#ifndef Counter_DL636G1_h
#define Counter_DL636G1_h

extern "C" {
#include <sys/types.h>
#include "sis3100_vme_calls.h"
}

#include "IOError.h"
#include "VmeModule.h"

/// see http://www.physi.uni-heidelberg.de/physi/ew/Geraete/DL636G_Counter/DL636G.pdf
/// for description of the DL636G1 Counter Module

class Counter_DL636G1 : public VmeModule
{
 public:
  static const int CMD_OFFSET  = 0x0;
  static const int STATUS_OFFSET = 0x0;
  static const int A_HI_OFFSET = 0x4;  //(in the manual A is refered as B1)
  static const int A_LO_OFFSET = 0x6;
  static const int B_HI_OFFSET = 0x8;  //(in the manual B is refered as B2)
  static const int B_LO_OFFSET = 0xA;  
  static const int C_HI_OFFSET = 0xC;  //(in the manual C is refered as B3)
  static const int C_LO_OFFSET = 0xE;

  Counter_DL636G1(int filehandle,unsigned int address) : VmeModule(filehandle,address) {}

  /// these methods are all implict inline, to save a funtion call
  /// which might be faster in the end
  u_int16_t getStatus() throw(IOError)
  {
    int r;
    u_int16_t status;

    if( (r=vme_A16D16_read(handle,address+STATUS_OFFSET,&status)) )
      throw IOError("Counter_DL636G1::getStatus(): vme_A16D16_read() returned non zero",r);

    return status;
  }

  /// returns gate-in status
  /// remark: the gate-out output is inverted!
  int getGateIn() throw(IOError)
  {
    int r;
    u_int16_t gate;

    if( (r=vme_A16D16_read(handle,address+STATUS_OFFSET,&gate)) )
      throw IOError("Counter_DL636G1::getStatus(): vme_A16D16_read() returned non zero",r);

    return (gate >> 15);
  }


  unsigned int getA() throw(IOError)
  {
    u_int16_t hi,lo;
    int r;

    if( (r=vme_A16D16_read(handle,address+A_HI_OFFSET,&hi)) != 0 )
      throw IOError("Counter_DL636G1::getA(): vme_A16D16_read() returned non zero",r);

    if( (r=vme_A16D16_read(handle,address+A_LO_OFFSET,&lo)) != 0 )
      throw IOError("Counter_DL636G1::getA(): vme_A16D16_read() returned non zero",r);

    return ( (hi << 16) | lo );
  }

  unsigned int getB() throw(IOError)
  {
    u_int16_t hi,lo;
    int r;

    if( (r=vme_A16D16_read(handle,address+B_HI_OFFSET,&hi)) != 0 )
      throw IOError("Counter_DL636G1::getB(): vme_A16D16_read() returned non zero",r);

    if( (r=vme_A16D16_read(handle,address+B_LO_OFFSET,&lo)) != 0 )
      throw IOError("Counter_DL636G1::getB(): vme_A16D16_read() returned non zero",r);

    return ( (hi << 16) | lo );
  }

  unsigned int getC() throw(IOError)
  {
    u_int16_t hi,lo;
    int r;

    if( (r=vme_A16D16_read(handle,address+C_HI_OFFSET,&hi)) != 0 )
      throw IOError("Counter_DL636G1::getC(): vme_A16D16_read() returned non zero",r);

    if( (r=vme_A16D16_read(handle,address+C_LO_OFFSET,&lo)) != 0 )
      throw IOError("Counter_DL636G1::getC(): vme_A16D16_read() returned non zero",r);

    return ( (hi << 16) | lo );
  }

  void reset() throw(IOError)
  {
    int r;

    if( (r=vme_A16D16_write(handle,address+CMD_OFFSET,0x8000))!=0 )
      throw IOError("Counter_DL636G1::reset(): vme_A16D16_write() returned non zero",r);
  }

};

#endif
